package com.gengzp.permission.core.impl;

import com.gengzp.permission.annotation.CheckPermission;
import com.gengzp.permission.core.PermissionCoreFunc;
import com.gengzp.permission.core.PermissionTokenProcessor;
import com.gengzp.permission.exception.PermissionException;
import com.gengzp.permission.model.UserPrincipalModel;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;

import java.util.Set;

import static com.gengzp.permission.constants.PermissionExceptionConstants.NO_AUTHENTICATED;
import static com.gengzp.permission.constants.PermissionExceptionConstants.NO_PERMISSION;
import static com.gengzp.permission.constants.PermissionRequestConstants.AUTH_HEADER_KEY;
import static com.gengzp.permission.constants.PermissionRequestConstants.BEARER_TOKEN_PREFIX;

/**
 * @ClassName PermissionTokenProcessorImplDefault
 * @Description 权限认证框架token处理器默认实现类
 * @Author gengzp
 * @Date 2025/8/15 13:47
 */
@Component
public class PermissionTokenProcessorImplDefault implements PermissionTokenProcessor {

    @Autowired
    private PermissionCoreFunc permissionCoreFunc;

    @Override
    public UserPrincipalModel parseAndVerifyRequestAuthentication(HttpServletRequest request, Object handler) throws PermissionException {
        // 获取当前请求头中携带的BearerToken信息
        String BearerToken = request.getHeader(AUTH_HEADER_KEY);
        if (BearerToken == null || BearerToken.isBlank()) {
            throw PermissionException.get(NO_AUTHENTICATED, "用户未登录，请先登录再访问该接口");
        }

        // 截取得到token信息
        String token = BearerToken.substring(BEARER_TOKEN_PREFIX.length());
        if (token.isBlank()) {
            throw PermissionException.get(NO_AUTHENTICATED, "用户认证信息不合法，请重新登录");
        }

        // 从redis中获取用户信息
        UserPrincipalModel userPrincipalModel = permissionCoreFunc.getCacheUserPrincipalModel(token);
        if (userPrincipalModel == null) {
            throw PermissionException.get(NO_AUTHENTICATED, "用户登录状态已过期，请重新登录");
        }

        // 获取超级管理员用户id
        String superAdminUserId = permissionCoreFunc.getSuperAdminUserId();

        // 验证当前用户是否为超级管理员, 超级管理员无需进行权限验证
        if (superAdminUserId == null || !superAdminUserId.equals(userPrincipalModel.getUserId())) {
            verifyPermission(handler, userPrincipalModel);
        }

        return userPrincipalModel;
    }

    /**
     * 校验用户的权限
     *
     * @param handler            方法处理器
     * @param userPrincipalModel 用户认证信息
     */
    private void verifyPermission(Object handler, UserPrincipalModel userPrincipalModel) throws PermissionException {
        // 判断当前接口方法上是否有权限注解 @CheckPermission, 只有添加了权限注解的接口方法才需要进行权限验证
        CheckPermission checkPermissionAnnotation = ((HandlerMethod) handler).getMethodAnnotation(CheckPermission.class);
        if (checkPermissionAnnotation == null) {
            return;
        }

        // 获取当前方法的权限注解中配置的权限编码
        String methodPermissionCode = checkPermissionAnnotation.value();

        // 根据当前用户拥有的角色id查询出所有权限编码
        Set<String> existPermissionCodes = permissionCoreFunc.getAllPermissionCodesByRoleIds(userPrincipalModel.getRoleIds());

        // 如果权限不足则抛出异常
        if (existPermissionCodes == null || existPermissionCodes.isEmpty() ||
                !String.join(",", existPermissionCodes).contains(methodPermissionCode)) {
            throw PermissionException.get(NO_PERMISSION, String.format("当前用户没有访问该接口的权限【%s】", methodPermissionCode));
        }
    }

}
